﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Data;
using Husb.Data;
using Husb.Util;
using GroundWater.Data;
using GroundWater.DataAccess;
using MonitoringTable = GroundWater.Data.MonitoringDataSet.MonitoringDataTable;
using MonitoringRow = GroundWater.Data.MonitoringDataSet.MonitoringRow;
using Husb.DataUtil;
using System.Globalization;

namespace GroundWater.BusinessActions
{
    public class Monitoring : DataAccessManager<MonitoringDataSet, MonitoringTable, MonitoringRow, MonitoringDataAdapter>
    {
        public static MonitoringTable FetchCriteria(string startDate, string endDate, decimal? minWaterLevel, decimal? maxWaterLevel, decimal? voltage)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchCriteria(startDate, endDate, minWaterLevel, maxWaterLevel, voltage);
        }

        public static MonitoringTable CheckWaterlevel(string startDate, string endDate, bool minWaterlevel)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            MonitoringTable tmp = adapter.FetchCriteria(startDate, endDate, null, null, null);

            if (tmp == null || tmp.Rows.Count == 0)
                return tmp;

            MonitoringTable table = new MonitoringDataSet.MonitoringDataTable();

            //tmp.ImportRow(table[0]);

            string wellCode = tmp[0].WellCode;
            string date = tmp[0].MonitorTime.ToString("yyyy-MM-dd");
            decimal waterlevel = tmp[0].Waterlevel;
            bool inserted = false;  // 用于控制当天的异常数据是否已经统计了，
            bool isAbnormal = false;// 用于控制当前记录的水位是否异常
            isAbnormal = minWaterlevel ? tmp[0].MinimumWaterlevel > 0 && tmp[0].Waterlevel <= tmp[0].MinimumWaterlevel : tmp[0].MaximumWaterlevel > 0 && tmp[0].Waterlevel >= tmp[0].MaximumWaterlevel;

            if (isAbnormal)
            {
                table.ImportRow(tmp[0]);
                inserted = true;
            }

            int p = 1;
            while (p < tmp.Count)
            {
                if (minWaterlevel && tmp[p].MinimumWaterlevel == 0)
                {
                    p++;
                    continue;
                }
                if (!minWaterlevel && tmp[p].MaximumWaterlevel == 0)
                {
                    p++;
                    continue;
                }

                isAbnormal = minWaterlevel ? tmp[p].Waterlevel <= tmp[p].MinimumWaterlevel : tmp[p].Waterlevel >= tmp[p].MaximumWaterlevel;
                if (isAbnormal)
                {
                    if (wellCode == tmp[p].WellCode && date == tmp[p].MonitorTime.ToString("yyyy-MM-dd") && inserted)
                    {
                        p++;
                        continue;
                    }
                    table.ImportRow(tmp[p]);
                    wellCode = tmp[p].WellCode;
                    date = tmp[p].MonitorTime.ToString("yyyy-MM-dd");
                    inserted = true;
                }
                else
                {
                    p++;
                    inserted = false;
                    continue;
                }
                p++;
            }

            return table;
        }

        public static MonitoringTable FetchWaterlevelWarning(string startDate, string endDate, decimal? minWaterLevel, decimal? maxWaterLevel)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            MonitoringTable min = adapter.FetchCriteria(startDate, endDate, minWaterLevel, null, null);

            MonitoringTable max = adapter.FetchCriteria(startDate, endDate, null, maxWaterLevel, null);

            min.Merge(max);

            return min;
        }


        public static DataTable FetchWaterLeveByDate(string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveByDate(startDate, endDate);
        }
        public static MonitoringTable FetchWaterLeveToday(string date)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveToday(date);
        }

        public static MonitoringTable FetchWaterLeveLast(string date)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            MonitoringTable table = adapter.FetchWaterLeveToday(date);
            if (table == null || table.Rows.Count == 0)
                return table;

            MonitoringTable tmp = new MonitoringDataSet.MonitoringDataTable();
            tmp.ImportRow(table[0]);

            string wellName = table[0].WellName;
            int p = 1;
            while (p < table.Count)
            {
                if (wellName == table[p].WellName)
                {
                    p++;
                    continue;
                }
                else
                {
                    tmp.ImportRow(table[p]);
                    wellName = table[p].WellName;
                }
                p++;
            }
            

            return tmp;
        }


        public static MonitoringRow FetchById(string wellCode, DateTime monitoringTime)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchById(wellCode, monitoringTime);
        }

        public static int Delete(string wellCode, DateTime monitoringTime)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.Delete(wellCode, monitoringTime);
        }


        public static MonitoringTable FetchPaged(string wellCode, string startDate, string endDate, string sortExpression, int maximumRows, int startRowIndex)
        {
            if (String.IsNullOrEmpty(wellCode))
            {
                wellCode = System.Configuration.ConfigurationManager.AppSettings["FirstWellCode"];// "000000000001";
            }
            if (String.IsNullOrEmpty(startDate))
            {
                startDate = DateTime.Now.AddDays(-10).ToString("yyyy-MM-dd");
            }
            if (String.IsNullOrEmpty(endDate))
            {
                endDate = DateTime.Now.ToString("yyyy-MM-dd");
            }
            if (String.IsNullOrEmpty(sortExpression))
            {
                sortExpression = "MNTM DESC";
            }
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchPaged(wellCode, startDate, endDate, sortExpression, maximumRows, startRowIndex);
        }

        public static int FetchRowCount(string wellCode, string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchRowCount(wellCode, startDate, endDate);
        }

        public static MonitoringTable FetchByDatePaged(string startDate, string endDate, string sortExpression, int maximumRows, int startRowIndex)
        {
            if (String.IsNullOrEmpty(startDate))
            {
                startDate = DateTime.Now.AddDays(-10).ToString("yyyy-MM-dd");
            }
            if (String.IsNullOrEmpty(endDate))
            {
                endDate = DateTime.Now.ToString("yyyy-MM-dd");
            }
            if (String.IsNullOrEmpty(sortExpression))
            {
                sortExpression = "MNTM DESC";
            }
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchByDatePaged(startDate, endDate, sortExpression, maximumRows, startRowIndex);
        }

        public static int FetchByDateRowCount(string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchByDateRowCount(startDate, endDate);
        }



        public static DataTable FetchSectionPlane()
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchSectionPlane();
        }

        public static DataTable FetchWaterLeveGroupByWellCode(string sectionPlane, string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveGroupByWellCode(sectionPlane, startDate, endDate);
        }

        public static DataTable FetchWaterLeveByWellCode(string wellCode, string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveByWellCode(wellCode, startDate, endDate);
        }

        public static DataTable FetchWaterLeveAllByDate(string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveAllByDate(startDate, endDate);
        }

        public static DataTable FetchWaterLeveBySectionPlane(string sectionPlane, string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveBySectionPlane(sectionPlane, startDate, endDate);
        }

        public static DataTable FetchWaterLeveAllBySectionPlane(string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveAllBySectionPlane(startDate, endDate);
        }

        /// <summary>
        /// 根据起止日期获取 按行政区域分组的水位数据
        /// </summary>
        /// <param name="startDate">起始日期</param>
        /// <param name="endDate">截至日期</param>
        /// <returns></returns>
        public static DataTable FetchWaterLeveByDivisionsCode(string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveByDivisionsCode(startDate, endDate);
        }

        /// <summary>
        /// 根据起止日期和行政区域 获取水位数据
        /// </summary>
        /// <param name="divisionsCode"></param>
        /// <param name="startDate"></param>
        /// <param name="endDate"></param>
        /// <returns></returns>
        public static DataTable FetchWaterLeveAvgByDivisionsCode(string divisionsCode, string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveAvgByDivisionsCode(divisionsCode, startDate, endDate);
        }

        public static DataTable FetchWaterLeveGroupByDate(string wellCode, string startDate, string endDate, int maxDay)
        {
            if (maxDay < 1) maxDay = 32;
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            DataTable dt = adapter.FetchWaterLeveGroupByDate(wellCode, startDate, endDate);

            if (dt == null || dt.Rows.Count == 0) return null;

            object d1 = dt.Rows[0]["MonitorTime"];
            object d2 = dt.Rows[dt.Rows.Count - 1]["MonitorTime"];


            DateTime dtStart = d1 == DBNull.Value ? DateTime.Parse(startDate) : DateTime.Parse(d1.ToString());
            DateTime dtEnd = d2 == DBNull.Value ? DateTime.Parse(startDate) : DateTime.Parse(d2.ToString());

            if (dt.Rows.Count < maxDay)
            {
                if (dtEnd.Subtract(dtStart).Days < maxDay)
                {
                    return dt;
                }
            }

            DataTable tmpTable = new DataTable();
            tmpTable.Columns.Add("MonitorTime", typeof(System.String));//Waterlevel
            tmpTable.Columns.Add("Waterlevel", typeof(System.Decimal));//
            tmpTable.Columns.Add("Date", typeof(System.String));

            PopulateDataByDay(tmpTable, dt);
            if (tmpTable.Rows.Count < maxDay)
            {
                if (dtEnd.Subtract(dtStart).Days < maxDay * 7)
                {
                    return tmpTable;
                }
            }

            PopulateDataByMonth(tmpTable, dt);
            if (tmpTable.Rows.Count < maxDay)
            {
                if (dtEnd.Subtract(dtStart).Days < maxDay * 30)
                {
                    return tmpTable;
                }
            }

            PopulateDataByQuarter(tmpTable, dt);
            if (tmpTable.Rows.Count < maxDay)
            {
                if (dtEnd.Subtract(dtStart).Days < maxDay * 93)
                {
                    return tmpTable;
                }
            }
            
            return tmpTable;
        }
        

        private static void PopulateData(DataTable tmpTable, DataTable dt)
        {
            decimal waterlevel = 0;
            int cnt = 0;
            int max = dt.Rows.Count;
            int p = 0;
            bool first = true;
            int week = 0;
            while (cnt < max)
            {
                if (first)
                {
                    DateTime date = DateTime.Parse(dt.Rows[cnt]["MonitorTime"].ToString());
                    //DayOfWeek week = date.DayOfWeek;
                    week = WeekOfYear(date);
                    int dayWeek = (int)(date.DayOfWeek);
                    if (dayWeek < 7)
                    {
                        p++;
                        waterlevel += (Decimal)dt.Rows[cnt]["Waterlevel"];
                    }

                    if (p > 0 && dayWeek == 0)
                    {
                        DataRow firstRow = tmpTable.NewRow();
                        firstRow["MonitorTime"] = week.ToString();
                        firstRow["Waterlevel"] = Math.Round(waterlevel / p, 2);
                        tmpTable.Rows.Add(firstRow);

                        waterlevel = 0;
                        p = 0;
                        first = false;
                    }
                    cnt++;
                    continue;
                }

                if (p < 7)
                {
                    waterlevel += (Decimal)dt.Rows[cnt]["Waterlevel"];
                    p++;
                }

                if (p == 7)
                {
                    week++;
                    DataRow tmpRow = tmpTable.NewRow();
                    tmpRow["MonitorTime"] = week.ToString();
                    tmpRow["Waterlevel"] = Math.Round(waterlevel / p, 2);
                    tmpTable.Rows.Add(tmpRow);

                    waterlevel = 0;
                    p = 0;
                }
                cnt++;
            }
        }

        private static void PopulateDataByDay(DataTable tmpTable, DataTable dt)
        {
            tmpTable.Clear();

            decimal waterlevel = 0;
            int cnt = 0;
            int max = dt.Rows.Count;
            int p = 0;
            
            //
            int weekOfYear = 0;
            DateTime date = DateTime.MinValue;
            System.Globalization.GregorianCalendar gc = new System.Globalization.GregorianCalendar();
            while (cnt < max)
            {
                var level = (Decimal)dt.Rows[cnt]["Waterlevel"];
                if (level < 0) continue;
                waterlevel += level;
                p++;

                date = DateTime.Parse(dt.Rows[cnt]["MonitorTime"].ToString());
                weekOfYear = gc.GetWeekOfYear(date, System.Globalization.CalendarWeekRule.FirstDay, DayOfWeek.Monday);
                int dayOfWeek = (int)(date.DayOfWeek);
                if (dayOfWeek == 0) dayOfWeek = 7;

                if (dayOfWeek == 7)
                {
                    AddRow(tmpTable, weekOfYear, waterlevel, date, p); 
                    waterlevel = 0;
                    p = 0;
                }
                cnt++;
            }
            if(p > 0)
            {
                AddRow(tmpTable, weekOfYear, waterlevel, date, p);
                waterlevel = 0;
                p = 0;
            }
            tmpTable.TableName = "Day";
        }

        private static void AddRow(DataTable tmpTable, int weekOfYear, decimal waterlevel, DateTime date, int p)
        {
            DataRow firstRow = tmpTable.NewRow();
            firstRow["MonitorTime"] = weekOfYear.ToString();
            firstRow["Waterlevel"] = Math.Round(waterlevel / p, 2);
            firstRow["Date"] = date.ToString("yyyyMMdd");
            tmpTable.Rows.Add(firstRow);
        }

        private static void PopulateDataByMonth(DataTable tmpTable, DataTable dt)
        {
            tmpTable.Clear();
            decimal waterlevel = 0;
            int cnt = 0;
            int max = dt.Rows.Count;
            int p = 0;

            if (max == 0) return;

            int curentMonth = DateTime.Parse(dt.Rows[0]["MonitorTime"].ToString()).Month;
            DateTime date = DateTime.MinValue;
            
            while (cnt < max)
            {
                date = DateTime.Parse(dt.Rows[cnt]["MonitorTime"].ToString());
                if (curentMonth != date.Month)
                {
                    AddRow(tmpTable, date.Month, waterlevel, date, p);
                    waterlevel = 0;
                    p = 0;
                }
                else
                {
                    var level = (Decimal)dt.Rows[cnt]["Waterlevel"];
                    if (level < 0) continue;
                    waterlevel += level;
                    p++;
                }
                curentMonth = date.Month;
                cnt++;
            }
            if (p > 0)
            {
                AddRow(tmpTable, date.Month, waterlevel, date, p);
                waterlevel = 0;
                p = 0;
            }
            tmpTable.TableName = "Month";
        }

        private static void PopulateDataByQuarter(DataTable tmpTable, DataTable dt)
        {
            tmpTable.Clear();
            decimal waterlevel = 0;
            int cnt = 0;
            int max = dt.Rows.Count;
            int p = 0;

            if (max == 0) return;

            int curentMonth = DateTime.Parse(dt.Rows[0]["MonitorTime"].ToString()).Quarter();
            DateTime date = DateTime.MinValue;

            while (cnt < max)
            {
                date = DateTime.Parse(dt.Rows[cnt]["MonitorTime"].ToString());
                if (curentMonth != date.Quarter())
                {
                    AddRow(tmpTable, date.Quarter(), waterlevel, date, p);
                    waterlevel = 0;
                    p = 0;
                }
                else
                {
                    var level = (Decimal)dt.Rows[cnt]["Waterlevel"];
                    if (level < 0) continue;
                    waterlevel += level;
                    p++;
                }
                curentMonth = date.Quarter();
                cnt++;
            }
            if (p > 0)
            {
                AddRow(tmpTable, date.Quarter(), waterlevel, date, p);
                waterlevel = 0;
                p = 0;
            }

            tmpTable.TableName = "Quarter";
        }
     

        //private static int WeekOfYear(DateTime dt)
        //{
        //    // 一年的第一天（阳历）
        //    DateTime firstDay = new DateTime(dt.Year, 1, 1);
        //    // 一年的第一天（阳历）
        //    DateTime lastDay = new DateTime(dt.Year, 12, 31);
        //    // 一年的第一天是周几
        //    int dayWeek = (int)(firstDay.DayOfWeek);

        //    CultureInfo cultureInfo = new CultureInfo("zh-CHS");
        //    System.Globalization.Calendar calendar = cultureInfo.Calendar;
        //    CalendarWeekRule weekRule = CalendarWeekRule.FirstDay;
        //    DayOfWeek dayOfWeek = DayOfWeek.Monday;

        //    DayOfWeek week = calendar.GetDayOfWeek(dt);

        //    int weeks = calendar.GetWeekOfYear(new DateTime(dt.Year, 12, 31), weekRule, dayOfWeek);


        //    return 0;
        //}

        public static int WeekOfYear(DateTime dt)
        {
            int week = 1;
            int nYear = dt.Year;
            System.DateTime firstDayInYear = new DateTime(nYear, 1, 1);
            System.DateTime lastDayInYear = new DateTime(nYear, 12, 31);
            int daysOfYear = Convert.ToInt32(lastDayInYear.DayOfYear);
            int weekNow = Convert.ToInt32(firstDayInYear.DayOfWeek) - 1;
            if (weekNow < 0) weekNow = 6;
            int dayAdd = 6 - weekNow;
            System.DateTime beginDayOfWeek = new DateTime(nYear, 1, 1);
            System.DateTime endDayOfWeek = beginDayOfWeek.AddDays(dayAdd);
            week = 2;
            for (int i = dayAdd + 1; i <= daysOfYear; i++)
            {
                beginDayOfWeek = firstDayInYear.AddDays(i);
                if (i + 6 > daysOfYear)
                {
                    endDayOfWeek = beginDayOfWeek.AddDays(daysOfYear - i - 1);
                }
                else
                {
                    endDayOfWeek = beginDayOfWeek.AddDays(6);
                }

                if (dt.Month == endDayOfWeek.Month && dt.Day <= endDayOfWeek.Day)
                {
                    break;
                }
                week++;
                i = i + 6;
            }
            return week;
        }


        public static DataTable FetchWaterLeveDataByDate(string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchWaterLeveDataByDate(startDate, endDate);
        }

        public static int UpdateConcurrencyByDate(string startDate, string endDate)
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.UpdateConcurrencyByDate(startDate, endDate);
        }

        /// <summary>
        /// 获取所有行政区域代码
        /// </summary>
        /// <returns></returns>
        public static DataTable FetchAllDivisionsCode()
        {
            MonitoringDataAdapter adapter = new MonitoringDataAdapter();
            return adapter.FetchAllDivisionsCode();
        }
    }
}
